
#if defined(WIN32) || defined(WIN64)
#pragma unmanaged
#endif

#include <Liberty3D/Engine/MemoryManager.h>
#include <Liberty3D/Engine/IMemoryListener.h>

#include <list>
#include <boost/thread/mutex.hpp>

using namespace Liberty::Engine;

boost::mutex*                              MemoryMutex     = nullptr;
std::list<std::weak_ptr<IMemoryListener>>* MemoryListeners = nullptr;

void MemoryManager::addListener(const std::shared_ptr<IMemoryListener>& listener) {
    if (MemoryMutex == nullptr) {
        MemoryMutex = new boost::mutex();
    }

    boost::lock_guard<boost::mutex> guard(*MemoryMutex);

    if (MemoryListeners == nullptr) {
        MemoryListeners = new std::list<std::weak_ptr<IMemoryListener>>();
    }
}

void MemoryManager::removeListener(const std::shared_ptr<IMemoryListener>& listener) {
    if (MemoryMutex == nullptr) {
        return;
    }

    boost::lock_guard<boost::mutex> guard(*MemoryMutex);

    if (MemoryListeners == nullptr) {
        return;
    }

    std::list<std::weak_ptr<IMemoryListener>>::iterator it, end(MemoryListeners->end());

    for (it = MemoryListeners->begin(); it != end; ++it) {
        if ((*it).expired()) {
            it = MemoryListeners->erase(it);
        }
        else if (listener == (*it).lock()) {
            it = MemoryListeners->erase(it);
        }
    }
}

void MemoryManager::memoryLow() {
    if (MemoryMutex == nullptr) {
        return;
    }

    boost::lock_guard<boost::mutex> guard(*MemoryMutex);

    if (MemoryListeners == nullptr) {
        return;
    }

    std::list<std::weak_ptr<IMemoryListener>>::iterator it, end(MemoryListeners->end());

    for (it = MemoryListeners->begin(); it != end; ++it) {
        std::shared_ptr<IMemoryListener> listener((*it).lock());

        if (listener) {
            listener->onMemoryLow();
        }
        else {
            it = MemoryListeners->erase(it);
        }
    }
}

void MemoryManager::garbageCollect() {
    if (MemoryMutex == nullptr) {
        return;
    }

    boost::lock_guard<boost::mutex> guard(*MemoryMutex);

    if (MemoryListeners == nullptr) {
        return;
    }

    std::list<std::weak_ptr<IMemoryListener>>::iterator it, end(MemoryListeners->end());

    for (it = MemoryListeners->begin(); it != end; ++it) {
        std::shared_ptr<IMemoryListener> listener((*it).lock());

        if (listener) {
            listener->onMemoryGarbageCollect();
        }
        else {
            it = MemoryListeners->erase(it);
        }
    }
}
